package com.wzb.mybatisplus.bitaction.electrumaction.five;

import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;
import java.security.*;
import java.util.Arrays;

public class BouncyCastleWIFConverter {

    private static final String BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

    public static void main(String[] args) {
        String wifPrivateKey = "5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF";

        try {
            // 从WIF提取私钥
            byte[] privateKeyBytes = extractPrivateKeyFromWIF(wifPrivateKey);
            BigInteger privateKey = new BigInteger(1, privateKeyBytes);

            // 使用Bouncy Castle生成公钥
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1");
            ECPoint publicPoint = spec.getG().multiply(privateKey);

            // 获取压缩公钥
            byte[] compressedPublicKey = publicPoint.getEncoded(true);

            // 生成比特币地址
            String bitcoinAddress = publicKeyToAddress(compressedPublicKey);

            System.out.println("WIF私钥: " + wifPrivateKey);
            System.out.println("私钥 (十六进制): " + String.format("%064x", privateKey));
            System.out.println("压缩公钥 (十六进制): " + bytesToHex(compressedPublicKey));
            System.out.println("比特币地址: " + bitcoinAddress);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static byte[] extractPrivateKeyFromWIF(String wifKey) {
        byte[] decoded = base58Decode(wifKey);

        // 验证校验和
        byte[] data = Arrays.copyOfRange(decoded, 0, decoded.length - 4);
        byte[] checksum = Arrays.copyOfRange(decoded, decoded.length - 4, decoded.length);

        byte[] hash1 = sha256(data);
        byte[] hash2 = sha256(hash1);
        byte[] calculatedChecksum = Arrays.copyOfRange(hash2, 0, 4);

        if (!Arrays.equals(checksum, calculatedChecksum)) {
            throw new IllegalArgumentException("WIF校验和失败");
        }

        // 提取私钥
        return Arrays.copyOfRange(data, 1, 33);
    }

    public static String publicKeyToAddress(byte[] publicKey) {
        // SHA256哈希
        byte[] sha256Hash = sha256(publicKey);

        // RIPEMD160哈希
        byte[] ripemd160Hash = ripemd160(sha256Hash);

        // 添加版本字节 (0x00 主网)
        byte[] versionedPayload = new byte[ripemd160Hash.length + 1];
        versionedPayload[0] = 0x00;
        System.arraycopy(ripemd160Hash, 0, versionedPayload, 1, ripemd160Hash.length);

        // 计算校验和
        byte[] checksum = Arrays.copyOfRange(sha256(sha256(versionedPayload)), 0, 4);

        // 组合最终数据
        byte[] addressBytes = new byte[versionedPayload.length + 4];
        System.arraycopy(versionedPayload, 0, addressBytes, 0, versionedPayload.length);
        System.arraycopy(checksum, 0, addressBytes, versionedPayload.length, 4);

        return base58Encode(addressBytes);
    }

    // 工具方法
    public static byte[] base58Decode(String input) {
        BigInteger num = BigInteger.ZERO;
        for (char c : input.toCharArray()) {
            num = num.multiply(BigInteger.valueOf(58))
                    .add(BigInteger.valueOf(BASE58.indexOf(c)));
        }
        byte[] bytes = num.toByteArray();
        return bytes[0] == 0 ? Arrays.copyOfRange(bytes, 1, bytes.length) : bytes;
    }

    public static String base58Encode(byte[] input) {
        BigInteger value = new BigInteger(1, input);
        StringBuilder sb = new StringBuilder();
        while (value.compareTo(BigInteger.ZERO) > 0) {
            BigInteger[] divmod = value.divideAndRemainder(BigInteger.valueOf(58));
            sb.insert(0, BASE58.charAt(divmod[1].intValue()));
            value = divmod[0];
        }
        for (byte b : input) {
            if (b == 0) sb.insert(0, '1');
            else break;
        }
        return sb.toString();
    }

    public static byte[] sha256(byte[] input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            return md.digest(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] ripemd160(byte[] input) {
        try {
            MessageDigest md = MessageDigest.getInstance("RIPEMD160");
            return md.digest(input);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}